#include "include/SecureTestWindow.h"
#include "lib/GBase64/include/b64.h"
#include <string>
#include <strstream>

using namespace std;

SecureTestWindow::SecureTestWindow()
    :InnerWindow("secure")
{
    if(this->crypt.Init("C:\\SVN\\green-lab\\wLBSTest\\wlbs_cert.pem") != 0)
        qDebug()<<"No crypto";

    QByteArray br((const char*)crypt.aes_key, crypt.aes_key_len);
    QString keyHex = br.toHex();

     pTcpSocket = new QTcpSocket(this);
     this->setupUi(this);

     this->textEdit_3->setText(keyHex);

     connect(pTcpSocket, SIGNAL(connected()), this, SLOT(connected()));
     connect(pTcpSocket, SIGNAL(disconnected()), this, SLOT(disconnected()));
     connect(pTcpSocket, SIGNAL(error(QAbstractSocket::SocketError)), this, SLOT(error(QAbstractSocket::SocketError)));
     connect(pTcpSocket, SIGNAL(readyRead()), this, SLOT(readyToRead()));
     connect(this->pushButton, SIGNAL(clicked()), this, SLOT(dwnPressed()));

     connect(this->radioButton, SIGNAL(clicked()), this, SLOT(clickedResponseBase()));
     connect(this->radioButton_2, SIGNAL(clicked()), this, SLOT(clickedResponseHex()));
     connect(this->radioButton_3, SIGNAL(clicked()), this, SLOT(clickedResponsePlain()));

     connect(this->radioButton_4, SIGNAL(clicked()), this, SLOT(clickedQueryBase()));
     connect(this->radioButton_5, SIGNAL(clicked()), this, SLOT(clickedQueryHex()));
     connect(this->radioButton_6, SIGNAL(clicked()), this, SLOT(clickedQueryPlain()));

     connect(this->radioButton_8, SIGNAL(clicked()), this, SLOT(clickedKeyBase()));
     connect(this->radioButton_7, SIGNAL(clicked()), this, SLOT(clickedKeyHex()));
     connect(this->radioButton_9, SIGNAL(clicked()), this, SLOT(clickedKeyPlain()));

     progressBar->setMaximum(0);
     progressBar->setMinimum(0);
     progressBar->hide();
}

SecureTestWindow::~SecureTestWindow()
{
}

void SecureTestWindow::clearInnerWindow()
{
}

void SecureTestWindow::connected()
{
    if(msg.isEmpty())
        return;

    //QString data = this->plainTextEdit->toPlainText();
    QString data = msg;
    string res;
    this->Encrypt(data.toStdString(), res);

    QByteArray br((const char*)crypt.enc_key, 256);
    QString keyHex = br.toBase64();
    qDebug()<<"connected();";
    std::string a = "<wlbs_handshake><key>" + keyHex.toStdString() + "</key>" + "</wlbs_handshake>";
    pTcpSocket->write(a.c_str());

    a = "<wlbs_enc>" + res + "</wlbs_enc>";
    pTcpSocket->write(a.c_str());
}

void SecureTestWindow::disconnected()
{
}

void SecureTestWindow::readyToRead()
{
    qDebug()<<"readyToRead();";
    qDebug()<<pTcpSocket->bytesAvailable();
    QByteArray bf = pTcpSocket->readAll();
    qDebug()<<bf;
    QString data = bf;

    int first = data.indexOf(QChar('>'), 0);
    int second = data.indexOf(QChar('<'), 5);
    qDebug()<<first<<" "<<second;

    QString base = data.mid(first + 1, second - first);
    baseEnc = base;
    qDebug()<<base;

    std::string in = base.toStdString();
    std::string out;
    Decrypt(in, out);

    plainEnc = QString(out.c_str());

    this->textEdit_2->setText(QString(out.c_str()));
    this->progressBar->hide();
}

void SecureTestWindow::error(QAbstractSocket::SocketError err)
{
    qDebug()<<"err: "<<err;
}

void SecureTestWindow::sendToServer()
{
}

void SecureTestWindow::dwnPressed()
{
    pTcpSocket->connectToHost("82.144.223.145", 7777);
    pushButton->hide();
    progressBar->show();
}

void SecureTestWindow::clickedResponseBase()
{
    this->textEdit_2->setText(baseEnc);
}
void SecureTestWindow::clickedResponseHex()
{
    this->textEdit_2->setText(baseEnc);
}
void SecureTestWindow::clickedResponsePlain()
{
    this->textEdit_2->setText(plainEnc);
}

void SecureTestWindow::clickedQueryBase()
{
    if(this->plainTextEdit->toPlainText().isEmpty())
        return;
    else
    {
        QString data = this->plainTextEdit->toPlainText();
        msg = data;
        string res;
        this->Encrypt(data.toStdString(), res);
        data = QString(res.c_str());
        this->plainTextEdit->setPlainText(data);
    }
    //if(this->textEdit_2->is)
}
void SecureTestWindow::clickedQueryHex()
{
    if(this->plainTextEdit->toPlainText().isEmpty())
        return;

    QString data1 = this->plainTextEdit->toPlainText();
    msg = data1;

    std::string in = plainTextEdit->toPlainText().toStdString();
    int enc = 32; /// Value for encryption purposes
    char data[1024];
    memset(data, 0, 1024);

    unsigned char* bb = crypt.aes_encrypt((unsigned char*) in.c_str(), in.length(), crypt.aes_key, &enc);

    std::strstream ss;
    //QByteArray br((const char*)crypt.enc_key, crypt.aes_key_len);
    QString keyHex;
    //this->textEdit_3->setText(br);
    for(int i = 0; i < enc; i++)
        ss<<i<<") "<<int(bb[i])<<"\n";
    ss<<"\0";
    keyHex = ss.str();
    this->plainTextEdit->setPlainText(keyHex);
}

void SecureTestWindow::clickedQueryPlain()
{
    this->plainTextEdit->setPlainText(msg);
}

void SecureTestWindow::clickedKeyBase()
{
    QByteArray br((const char*)crypt.enc_key, 256);
    QString keyHex = br.toBase64();
    this->textEdit_3->setText(keyHex);
}
void SecureTestWindow::clickedKeyHex()
{
    msg = plainTextEdit->toPlainText();
    std::strstream ss;
    //QByteArray br((const char*)crypt.enc_key, crypt.aes_key_len);
    QString keyHex;
    //this->textEdit_3->setText(br);
    for(int i =0; i < crypt.aes_key_len; i++)
        ss<<i<<") "<<int(crypt.aes_key[i])<<"\n";
    ss<<"\0";
    keyHex = ss.str();
    this->textEdit_3->setText(keyHex);
}
void SecureTestWindow::clickedKeyPlain()
{
    std::strstream ss;
    //QByteArray br((const char*)crypt.enc_key, crypt.aes_key_len);
    QString keyHex;
    //this->textEdit_3->setText(br);
    for(int i =0; i < 256; i++)
        ss<<i<<") "<<int(crypt.enc_key[i])<<"\n";
    ss<<"\0";
    keyHex = ss.str();
    this->textEdit_3->setText(keyHex);
}

/// \todo use qca (win32 issues)
int SecureTestWindow::Encrypt(std::string in, std::string &out)
{
    GCrypt& uCrypter = crypt;

    /// Crypter object has to be properly initialized
    int enc = 32; /// Value for encryption purposes
    char data[1024];
    memset(data, 0, 1024);

    unsigned char* bb = uCrypter.aes_encrypt((unsigned char*) in.c_str(), in.length(), uCrypter.aes_key, &enc);
    B64_NAMESPACE::b64_encode(bb, enc, data, 1024);
    out = data; /// Get encrypted data
    if (out.empty())
        return -1;
    return 0;
}

int SecureTestWindow::Decrypt(std::string in, std::string &out)
{
    GCrypt& uCrypter = crypt;

    char buffer[2048];
    memset(buffer,0,2048);
    B64_NAMESPACE::b64_decode(in.c_str(), in.length(), buffer, 2048);
    out = ((const char*) uCrypter.aes_decrypt((unsigned char*) buffer, 2048, uCrypter.aes_key));
    if (out.empty()) /// Decryption failed
        return -1;
    return 0;
}
